package edu.sfsu.powerrangers.jeopardy.server;

import java.io.File;
import java.util.Collections;
import java.util.Comparator;
import java.util.Vector;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import edu.sfsu.powerrangers.jeopardy.gamestate.*;

public class GameReader {
	public Game[] readGames(File gameFile) {
		Vector<Game> games = new Vector<Game>();
		readGames(gameFile, games);
		Collections.sort(games, new Comparator<Game>() {
			public int compare(Game a, Game b) {
				return a.getName().compareToIgnoreCase(b.getName());
			}
		});
		return games.toArray(new Game[0]);
	}
	
	private void readGames(File gameFile, Vector<Game> games) {
		if (gameFile.isDirectory()) {
			for (File file : gameFile.listFiles()) {
				String name = file.getName();
				if (name.startsWith(".") || name.endsWith("\n") || name.endsWith("\r") || name.endsWith("\uF00A") || name.endsWith("\uF00D")) {
					continue;
				} else if (file.isDirectory() || name.endsWith(".wtq.xml") || name.endsWith(".wtq")) {
					readGames(file, games);
				}
			}
		} else try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			factory.setValidating(true);
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document document = builder.parse(gameFile);
			NodeList nl = document.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node n = nl.item(i);
				String nn = n.getNodeName();
				if (nn.equalsIgnoreCase("game")) {
					Game game = readGame(n);
					if (game != null) games.add(game);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private Game readGame(Node game) {
		String name = null;
		String description = null;
		Vector<Round> rounds = new Vector<Round>();
		FinalRound finalRound = null;
		NodeList nl = game.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node n = nl.item(i);
			String nn = n.getNodeName();
			if (nn.equalsIgnoreCase("name")) {
				name = n.getTextContent().replaceAll("\\s+", " ").trim();
			}
			else if (nn.equalsIgnoreCase("description")) {
				description = n.getTextContent().replaceAll("\\s+", " ").trim();
			}
			else if (nn.equalsIgnoreCase("round")) {
				Round round = readRound(n);
				if (round != null) rounds.add(round);
			}
			else if (nn.equalsIgnoreCase("finalround")) {
				FinalRound round = readFinalRound(n);
				if (round != null) finalRound = round;
			}
		}
		if (name != null && description != null && !rounds.isEmpty()) {
			Game g = new Game(name, description);
			g.addAll(rounds);
			g.setFinalRound(finalRound);
			return g;
		} else {
			return null;
		}
	}
	
	private Round readRound(Node round) {
		Vector<Category> categories = new Vector<Category>();
		NodeList nl = round.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node n = nl.item(i);
			String nn = n.getNodeName();
			if (nn.equalsIgnoreCase("category")) {
				Category category = readCategory(n);
				if (category != null) categories.add(category);
			}
		}
		if (!categories.isEmpty()) {
			Round r = new Round();
			r.addAll(categories);
			return r;
		} else {
			return null;
		}
	}
	
	private Category readCategory(Node category) {
		String name = null;
		Vector<Clue> clues = new Vector<Clue>();
		NodeList nl = category.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node n = nl.item(i);
			String nn = n.getNodeName();
			if (nn.equalsIgnoreCase("name")) {
				name = n.getTextContent().replaceAll("\\s+", " ").trim();
			}
			else if (nn.equalsIgnoreCase("clue")) {
				Clue clue = readClue(n);
				if (clue != null) clues.add(clue);
			}
		}
		if (name != null && !clues.isEmpty()) {
			Category c = new Category(name);
			c.addAll(clues);
			return c;
		} else {
			return null;
		}
	}
	
	private Clue readClue(Node clue) {
		int value = 0;
		boolean isDouble = false;
		String text = null;
		String response = null;
		NodeList nl = clue.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node n = nl.item(i);
			String nn = n.getNodeName();
			if (nn.equalsIgnoreCase("value")) {
				try {
					value = Integer.parseInt(n.getTextContent().replaceAll("\\s+", " ").trim());
				} catch (NumberFormatException nfe) {
					value = 0;
				}
			}
			else if (nn.equalsIgnoreCase("double")) {
				isDouble = true;
			}
			else if (nn.equalsIgnoreCase("text")) {
				text = n.getTextContent().replaceAll("\\s+", " ").trim();
			}
			else if (nn.equalsIgnoreCase("response")) {
				response = n.getTextContent().replaceAll("\\s+", " ").trim();
			}
		}
		if (value > 0 && text != null && response != null) {
			return new Clue(value, isDouble, text, response);
		} else {
			return null;
		}
	}
	
	private FinalRound readFinalRound(Node round) {
		String name = null;
		String text = null;
		String response = null;
		NodeList nl = round.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node n = nl.item(i);
			String nn = n.getNodeName();
			if (nn.equalsIgnoreCase("name")) {
				name = n.getTextContent().replaceAll("\\s+", " ").trim();
			}
			else if (nn.equalsIgnoreCase("text")) {
				text = n.getTextContent().replaceAll("\\s+", " ").trim();
			}
			else if (nn.equalsIgnoreCase("response")) {
				response = n.getTextContent().replaceAll("\\s+", " ").trim();
			}
		}
		if (name != null && text != null && response != null) {
			return new FinalRound(name, text, response);
		} else {
			return null;
		}
	}
}
